package com.icoolkj.learn.juc.base.communication;

import com.icoolkj.learn.juc.base.utils.SleepTools;
import lombok.extern.slf4j.Slf4j;

import java.util.LinkedList;
import java.util.Queue;

/**
 * @author icoolkj
 * @version 1.0
 * @description 实现生产者-消费者模型
 * @createDate 2025/03/05 12:18
 */
@Slf4j
public class ProducerConsumerModel {

    // 共享队列
    private final Queue<Integer> queue = new LinkedList<>();
    // 队列的容量
    private final int MAX_SIZE = 10;

    // 生产者方法
    public void produce(int item) throws InterruptedException {
        synchronized (queue){
            // 如果队列已满，则等待
            while (queue.size() == MAX_SIZE){
                queue.wait();
            }
            // 生产物品
            queue.add(item);
            log.info("Produced {}", item);
            // 通知可能正在等待的消费者
            queue.notifyAll();
        }
    }

    // 消费者方法
    public void consume(int item) throws InterruptedException {
        synchronized (queue){
            // 如果队列为空，则等待
            while (queue.size() == 0){
                queue.wait();
            }
            // 消费物品
            queue.remove(item);
            log.info("Consumed {}", item);
            // 通知可能正在等待的生产者
            queue.notifyAll();
        }
    }

    public static void main(String[] args) {
        ProducerConsumerModel model = new ProducerConsumerModel();
        // 创建并启动生产者线程
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 20; i++) {
                try {
                    model.produce(i);
                    // 模拟生产延迟
                    SleepTools.milliseconds(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }, "t1");

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 20; i++) {
                try {
                    model.consume(i);
                    // 模拟消费延迟
                    SleepTools.second(2);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }, "t2");

        t1.start();
        t2.start();

        // 等待两个线程完成
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
